package com.kfm.jdbc.day0328;

import com.kfm.jdbc.day0327.Recover;
import com.kfm.jdbc.day0328.entity.Goods;
import com.mysql.cj.jdbc.MysqlDataSource;

import javax.swing.*;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import static java.util.Locale.ENGLISH;

/**
 * 操作数据库的工具类
 */
public class DBUtils<T> {



    private PreparedStatement statement;

    private static Properties prop;

    private ResultSet resultSet;

    private ConnectionPool pool;

    static {
        InputStream in = DBUtils.class.getResourceAsStream("db.properties");
        Properties properties = new Properties();
        try {
            properties.load(in);
            DBUtils.prop = properties;
            try {
                Class.forName(properties.getProperty("jdbc.driver"));
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public DBUtils(int size){
        if (prop != null){
            String url = prop.getProperty("jdbc.url");
            String user = prop.getProperty("jdbc.user");
            String password = prop.getProperty("jdbc.password");
            pool = new ConnectionPool(size, url, user, password);
        } else {
            throw new NullPointerException("未设置数据库配置文件");
        }
    }

    public DBUtils(int size, String url, String user, String password){
        pool = new ConnectionPool(size, url, user, password);
    }

    public Connection getConnection(){
        if (pool != null){
            return pool.getConnection();
        }
        throw new NullPointerException("数据库连接参数未设置");
    }


    public T selectOne(String sql, Class<T> cla, Object...params){
        // try-with-resources
        try {
            executeSQL(sql, params);

            resultSet = statement.executeQuery();

            if (resultSet.next()){
                return mapper(resultSet, cla);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    public List<T> select(String sql, Class<T> cla, Object...params){
        // try-with-resources
        try {
            executeSQL(sql, params);

            resultSet = statement.executeQuery();

            List<T> list =  new ArrayList<>();
            while (resultSet.next()){
                list.add(mapper(resultSet, cla));
            }
            return list;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private T mapper(ResultSet resultSet, Class<T> cla){
        try {
            Constructor<T> declaredConstructor = cla.getDeclaredConstructor();
            T t = declaredConstructor.newInstance();

            // 元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
//                String columnName = metaData.getColumnName(i);
                String columnLabel = metaData.getColumnLabel(i);
                Object value = resultSet.getObject(columnLabel);
                if (value == null){
                    continue;
                }

                if (value instanceof Temporal) {
                    value = resultSet.getDate(columnLabel);
                }

                if (columnLabel.contains("_")){
                    String[] s = columnLabel.split("_");
                    StringBuilder sb = new StringBuilder(s[0]);
                    for (int j = 1; j < s.length; j++) {
                        sb.append(capitalize(s[j]));
                    }
                    columnLabel = sb.toString();
                }



                PropertyDescriptor property = new PropertyDescriptor(columnLabel, cla);
                Method writeMethod = property.getWriteMethod();
                // 防止不能访问
//                writeMethod.setAccessible(true);
                // 设置值
                writeMethod.invoke(t, value);
            }

            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public int update(String sql, Object...params){
        // try-with-resources
        try {
            executeSQL(sql, params);
            return statement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void executeSQL(String sql, Object...params){
        try {
            Connection conn = getConnection();
            statement = conn.prepareStatement(sql);

            // 设置值
            for (int i = 0; i < params.length; i++) {
                statement.setObject(i + 1, params[i]);
            }
            System.out.println(statement);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void release(Connection conn){
        pool.release(conn);
    }
    public void close(){
        try {
            if (resultSet != null) {
                resultSet.close();
            }

            if (statement != null) {
                statement.close();
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private static String capitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
    }

    public static void main(String[] args) {
        String columnLabel = "girl_friend_no";
        if (columnLabel.contains("_")){
            String[] s = columnLabel.split("_");
            StringBuilder sb = new StringBuilder(s[0]);
            for (int j = 1; j < s.length; j++) {
                sb.append(capitalize(s[j]));
            }
            columnLabel = sb.toString();
        }

        System.out.println(columnLabel);
    }

    public void insertBatch(String sql, List<Goods> list) {
        Connection conn = getConnection();
        try {
            conn.setAutoCommit(false);
            statement = conn.prepareStatement(sql);

            // TODO(这里写死为 Goods)
            for (Goods t : list) {
                statement.setObject(1, t.getGoodsName());
                statement.setObject(2, t.getCost());
                statement.setObject(3, t.getPrice());
                statement.setObject(4, t.getCount());
                statement.setObject(5, t.getCreateTime());
                statement.setObject(6, t.getCategoryNo());

                statement.addBatch();
            }
            statement.executeBatch();
            conn.commit();
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        }
    }
}
